﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dycox.Workflows.Conditions;

namespace Dycox.Workflows
{
    public class Transition
    {

        public Transition(Stage sourceStage, Stage targetStage)
        {
            if (sourceStage == null)
                throw new ArgumentNullException("sourceStage");
            if (targetStage == null)
                throw new ArgumentNullException("stage");
            if (sourceStage.Workflow != targetStage.Workflow)
                throw new ArgumentException("Workflow of source and target stage is not same.");
            if (sourceStage is NoMoreStepStage)
                throw new WorkflowException("EndOfThread stage can be used only on target.");
            if (sourceStage.Usage == StageUsage.PlaceHolder && targetStage.Usage == StageUsage.PlaceHolder)
                throw new WorkflowException("Both source and target stage are place-holder.");

            _targetStage = targetStage;
            _sourceStage = sourceStage;
            _workflow = sourceStage.Workflow;
        }

        private TransitionConditionCollection _conditions;

        public TransitionConditionCollection Conditions
        {
            get
            {
                if (_conditions == null)
                    _conditions = new TransitionConditionCollection(this);
                return _conditions;
            }
        }

        private Stage _targetStage;

        public Stage TargetStage
        {
            get { return _targetStage; }
        }

        public UserSelectedCondition UserSelection
        {
            get
            {
                if (_conditions == null || _conditions.Count == 0)
                    return null;
                return _conditions[0] as UserSelectedCondition;
            }
        }

        public bool UserSelectable
        {
            get
            {
                return UserSelection != null;
            }
        }

        private Stage _sourceStage;

        public Stage SourceStage
        {
            get { return _sourceStage; }
        }

        private Workflow _workflow;

        public Workflow Workflow
        {
            get { return _workflow; }
        }

        private int _rank;

        public int Rank
        {
            get { return _rank; }
            set
            {
                _rank = value;
            }
        }

        private StepMarshalling _stepMarshalling;

        public StepMarshalling StepMarshalling
        {
            get { return _stepMarshalling; }
            set { _stepMarshalling = value; }
        }

        private TransitionOperationCollection _operations;

        public TransitionOperationCollection Operations
        {
            get
            {
                if (_operations == null)
                    _operations = new TransitionOperationCollection(this);
                return _operations;
            }
        }

        private TransitionTypes? _type;

        public TransitionTypes Type
        {
            get
            {
                if (_type == null)
                {
                    StageUsage us, ut;

                    us = _sourceStage.Usage;
                    ut = _targetStage.Usage;

                    if (us == StageUsage.PlaceHolder)
                    {
                        _type = TransitionTypes.EnterStage;
                    }
                    else if (ut == StageUsage.PlaceHolder)
                    {
                        if (_targetStage is NoMoreStepStage)
                            _type = TransitionTypes.NoMoreStep;
                        else
                            _type = TransitionTypes.ExitStage;
                    }
                    else
                        _type = TransitionTypes.Normal;

                }

                return _type.Value;
            }
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            var type = this.Type;

            sb.Append(type.ToString());
            if (_sourceStage.Usage != StageUsage.PlaceHolder)
                sb.Append(_sourceStage.Name);
            if (_targetStage.Usage != StageUsage.PlaceHolder)
            {
                if (type == TransitionTypes.Normal)
                {
                    sb.Append(" => ");
                    sb.Append(_targetStage.Name);
                }
            }
            return sb.ToString();
        }
    }


    [Flags]
    public enum TransitionTypes
    {
        None = 0,
        /// <summary>
        /// Normal means transit a non-placeholder stage to another non-placeholder stage.
        /// </summary>
        Normal = 1,
        /// <summary>
        /// Transit from a non-placeholder stage to the situation that thread has no more step.
        /// </summary>
        NoMoreStep = 2,
        /// <summary>
        /// The very beginning of a process, that is, before the entrance.
        /// </summary>
        EnterStage = 0x100,
        /// <summary>
        /// A step is about to complete, regardless of following steps.
        /// </summary>
        ExitStage = 0x200,
        All = Normal | NoMoreStep | EnterStage | ExitStage,
    }
}
